#include <fstream>
#include <iostream>
extern "C" {
#include "libavcodec/packet.h"
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/log.h>
#include <libavutil/opt.h>
}
#include "xvideo_view.h"

using namespace std;

int main(int argc, char *argv[]) {
  auto view = XVideoView::Create(XVideoView::RenderType::SDL);

  string filename = "test.h264";
  ifstream ifs(filename, ios::binary);
  if (!ifs.is_open()) {
    cout << "open file error" << endl;
    return -1;
  }
  unsigned char inbuf[4096] = {0};
  AVCodecID codec_id = AV_CODEC_ID_H264;
  // 1. 查找解码器
  AVCodec *codec = avcodec_find_decoder(codec_id);
  if (!codec) {
    cout << "avcodec_find_decoder error" << endl;
    return -1;
  }
  // 2. 创建解码器上下文
  AVCodecContext *avctx = avcodec_alloc_context3(codec);
  if (!avctx) {
    cout << "avcodec_alloc_context3 error" << endl;
    return -1;
  }
  // 3. 打开上下文
  int ret = avcodec_open2(avctx, nullptr, NULL);
  // 4. 分割上下文
  AVCodecParserContext *parser = av_parser_init(codec_id);
  if (!parser) {
    cout << "av_parser_init error" << endl;
    return -1;
  }
  auto pkt = av_packet_alloc();
  auto frame = av_frame_alloc();
  auto begin = NowMs();
  bool is_init_win = false;
  int count = 0;
  while (!ifs.eof()) {
    ifs.read((char *)inbuf, sizeof(inbuf));
    int data_size = ifs.gcount();
    if (data_size <= 0) {
      break;
    }
    auto data = inbuf;
    while (data_size > 0) {
      // 通过startcode
      int ret = av_parser_parse2(parser, avctx, &pkt->data, &pkt->size, data,
                                 data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
      data_size -= ret;
      data += ret;
      if (pkt->size > 0) {
        cout << "size:" << pkt->size << endl;
        ret = avcodec_send_packet(avctx, pkt);
        if (ret < 0)
          break;
        while (ret >= 0) {
          ret = avcodec_receive_frame(avctx, frame);
          if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            break;
          else if (ret < 0) {
            cout << "avcodec_receive_frame error" << endl;
            return -1;
          }
          if (!is_init_win) {
            view->Init(frame->width, frame->height,
                       XVideoView::Format(frame->format));
            is_init_win = true;
          }
          view->DrawFrame(frame);
          count++;
          auto cur = NowMs();
          if (cur - begin > 1000) {
            cout << "\nfps:" << count << endl;
            count = 0;
            begin = cur;
          }
        }
      }
    }
  }
  ret = avcodec_send_packet(avctx, nullptr);
  while (ret >= 0) {
    ret = avcodec_receive_frame(avctx, frame);
    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
      break;
    else if (ret < 0) {
      cout << "avcodec_receive_frame error" << endl;
      return -1;
    }
  }
  if (parser)
    av_parser_close(parser);
  if (frame) {
    av_frame_free(&frame);
  }
  if (avctx)
    avcodec_free_context(&avctx);
  if (pkt)
    av_packet_free(&pkt);
}